背景
在搜索tensorflow(TF)相关的资料时候,发现在github上有比较多的example,其实在学习其他新内容,总是会有类似effectiveC++,efftiveGo,effectiveScala等类似总结,尝试搜了下effectiveTensorflow,发现这里还是有一个可以参考
同时还有一个star较高的examples作为学习的tutorial,地址在这里
本文打算从example这里开始,打算以此作为基础,先将tf相关的所有api尽可能熟悉,然后基于effective系列来了解常规的code style,最后再深入tf的基础架构、设计原理去深层次的了解。
开始之前,先看下两种编程模式的对比:符号编程以及命令式编程,即symbol style以及imperative style。符号式编程一般是将变量定义在一个计算图上,这个计算图指定了输入到输出的闭路,在计算图上指定变量之间的关系,此时对计算图进行编译输出的话,是没有任何输出的,仅仅当需要运算的输入放入后,才会在模型中形成数据流,形成输出。
1 | import tensorflow as tf |
这里可以看到的d还是一个Tensor,并不会输出最终的结果。
1 | a = tf.constant(1, name="input1") |
这里的tf.constant是一个Operation,简称Op,每个Op都以tensor作为参数,这里会将标量1,2转成tensor作为constant的输入。
这个时候通过print tf.get_default_graph().as_graph_def()查看计算图,可以看到
1 |
|
这里可以看到打印出来pb形式的计算图,显示了3个node,都是Op,计算图内部做了名称表达,如Const,Const_1,Add类似的名字;其中Const两个Op,还有attr属性,定义了了具体value的属性,如Key:”Value”表示Op接收的参数是tensor,类型是DT_UINT32,tensor_shape为空,应该默认是1维的,说明tf.constant将标量1,2转变成了tensor;最后看下Add这个op,从图的pb来看,没有value相关的attr,但是有多个input字段,都是Add这个Op的输入。
接下来,当我们定义一个Variable,再次show出graph,会看到如下内容
1 | node { |
可以看到,仅仅增加一个Variable,就增加了很多Op,包括Assign、Identity,VariableV2等Op node。这里面的原理目前还不可知,等待后续对原理深究再说,这里先不表。
tf提供一种eager lib,基于此可以实现impreative style的编程形式。相对于eager style,可以明显感受,构建计算图最终通过session来run的形式比较简单,在run之前只需要关注计算图本身的构建过程。
tf.reduce_sum(a,axis) ,如果不指定按照axis,那么就是全部相加起来得到一个值得tensor。axis则是指定按照哪个维度进行reduce,如果axis=0,那么按列来reduce;如果axis=1则按照行来reduce 如
1 | a = tf.constant([[1,1,1],[3,4,5]]) |
此时的b为[4,5,6],c和d是一样的,都是按照行来reduce,得到[3,12],可以看到维度降低到2了。reduce实现了降维。而e则是[15],不指定axis的话,则将所有元素按照sum进行reduce,得到一个值得tensor。
复现mnist的例子
1 | import tensorflow as tf |
在sess run之前都是在构建计算图,这里重点解释几点
1 首先使用tf.nn模块中softmax来进行多分类;cost的计算方式是batch的loss进行相加并取平均
一个image的loss计算方式是
1 | one_loss = tf_reduce_sum(-y*tf.log(pred),1), y与pred都是tensor,所以需要设置axis=1,表示在行上进行reduce,也就是一个image的所有列上的计算结果汇聚成一个tensor:[loss1, loss2, loss3],然后将结果再进行一次reduce_mean,就获取本次batch上的所有image的loss的均值了。 |
函数tf.argmax与tf.arg_max用法相同,建议用前者,后者即将deprecated。同理,tf.argmin与tf.arg_min是一样的道理。